// Converts a datatransfer structer into an object with all paths and files
// listed out. Returns a promise that resolves with the file structure.
function dataTransferToFiles(dataTransfer) {

    if (!(dataTransfer instanceof DataTransfer)) {

        throw new Error('Data must be of type "DataTransfer"', dataTransfer);

    }

    const files = {};

    // recurse down the webkit file structure resolving
    // the paths to files names to store in the `files`
    // object
    function recurseDirectory(item) {

        if (item.isFile) {

            return new Promise(resolve => {
                item.file(file => {
                    files[item.fullPath] = file;
                    resolve();
                });
            });

        } else {

            const reader = item.createReader();

            return new Promise(resolve => {

                const promises = [];

                // exhaustively read all the directory entries
                function readNextEntries() {

                    reader.readEntries(et => {

                        if (et.length === 0) {

                            Promise.all(promises).then(() => resolve());

                        } else {

                            et.forEach(e => {

                                promises.push(recurseDirectory(e));

                            });
                            readNextEntries();

                        }

                    });

                }

                readNextEntries();

            });
        }
    }

    return new Promise(resolve => {

        // Traverse down the tree and add the files into the zip
        const dtitems = dataTransfer.items && [...dataTransfer.items];
        const dtfiles = [...dataTransfer.files];

        if (dtitems && dtitems.length && dtitems[0].webkitGetAsEntry) {

            const promises = [];
            for (let i = 0; i < dtitems.length; i++) {
                const item = dtitems[i];
                const entry = item.webkitGetAsEntry();

                promises.push(recurseDirectory(entry));

            }
            Promise.all(promises).then(() => resolve(files));

        } else {

            // add a '/' prefix to math the file directory entry
            // on webkit browsers
            dtfiles
                .filter(f => f.size !== 0)
                .forEach(f => files['/' + f.name] = f);

            resolve(files);

        }
    });
}
export function registerDragEvents(viewer, callback) {

    document.addEventListener('dragover', e => e.preventDefault());
    document.addEventListener('dragenter', e => e.preventDefault());
    document.addEventListener('drop', e => {

        e.preventDefault();

        // convert the files
        dataTransferToFiles(e.dataTransfer)
            .then(files => {

                // removes '..' and '.' tokens and normalizes slashes
                const cleanFilePath = path => {

                    return path
                        .replace(/\\/g, '/')
                        .split(/\//g)
                        .reduce((acc, el) => {

                            if (el === '..') acc.pop();
                            else if (el !== '.') acc.push(el);
                            return acc;

                        }, [])
                        .join('/');

                };

                // set the loader url modifier to check the list
                // of files
                const fileNames = Object.keys(files).map(n => cleanFilePath(n));
                viewer.urlModifierFunc = url => {

                    // find the matching file given the requested url
                    const cleaned = cleanFilePath(url.replace(viewer.package, ''));
                    const fileName = fileNames
                        .filter(name => {

                            // check if the end of file and url are the same
                            const len = Math.min(name.length, cleaned.length);
                            return cleaned.substr(cleaned.length - len) === name.substr(name.length - len);

                        }).pop();

                    if (fileName !== undefined) {

                        // revoke the url after it's been used
                        const bloburl = URL.createObjectURL(files[fileName]);
                        requestAnimationFrame(() => URL.revokeObjectURL(bloburl));

                        return bloburl;

                    }

                    return url;

                };

                // set the source of the element to the most likely intended display model
                const filesNames = Object.keys(files);
                viewer.up = '+Z';
                document.getElementById('up-select').value = viewer.up;

                viewer.urdf =
                    filesNames
                        .filter(n => /urdf$/i.test(n))
                        .shift();

            });

        callback();
    });

}
